home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / score.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  22.9 KB  |  957 lines  |  [TEXT/R*ch]

  1. /* Scores and scoring in Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* Scoring in Xconq does not happen by default; instead a game design
  11.    may include one or more "scorekeepers", which are objects with properties
  12.    that define how winning and losing will be decided.
  13.  
  14.    There are two kinds of functionality in scorekeepers.  One kind is the
  15.    ability to end a game based on a specified condition, such as "the Star
  16.    of Satyria enters Noblum".  The other is the accumulation of a numeric score.
  17.    A scorekeeper may include both, so it can (for instance) end the game the
  18.    instant that a player's score reaches 100, or 100 more than another player,
  19.    or whatever.  */
  20.  
  21. #include "conq.h"
  22. extern FILE *open_scorefile_for_reading PARAMS ((char *name));
  23. extern FILE *open_scorefile_for_writing PARAMS ((char *name));
  24.  
  25. int read_scorefile PARAMS ((void));
  26. int interp_score_record PARAMS ((Obj *form));
  27.  
  28. typedef struct a_score_record {
  29.     char *gamename;
  30.     Obj *sides;
  31.     Obj *raw;
  32.     struct a_score_record *next;
  33. } ScoreRecord;
  34.  
  35. /* Iteration over all recorded scores. */
  36.  
  37. #define for_all_score_records(sr)  \
  38.   for ((sr) = records;  (sr) != NULL;  (sr) = (sr)->next)
  39.  
  40. ScoreRecord *records;
  41.  
  42. ScoreRecord *last_record;
  43.  
  44. /* This is true when the given side should be tested against the given scorekeeper. */
  45.  
  46. #define scorekeeper_applicable(side,sk)  \
  47.   ((side)->ingame && (side_in_set((side), (sk)->whomask)))
  48.  
  49. static void eval_sk_last_side_wins PARAMS ((Scorekeeper *sk));
  50.  
  51. /* The head of the list of scorekeepers. */
  52.  
  53. Scorekeeper *scorekeepers;
  54.  
  55. /* The end of the list of scorekeepers. */
  56.  
  57. Scorekeeper *last_scorekeeper;
  58.  
  59. /* The total number of scorekeepers defined. */
  60.  
  61. int numscorekeepers;
  62.  
  63. int nextskid;
  64.  
  65. /* The number of scorekeepers maintaining numeric scores. */
  66.  
  67. int numscores;
  68.  
  69. /* True if any pre-turn scorekeepers are defined. */
  70.  
  71. int any_pre_turn_scores;
  72.  
  73. /* True if any post-turn scorekeepers are defined. */
  74.  
  75. int any_post_turn_scores;
  76.  
  77. /* True if any post-action scorekeepers are defined. */
  78.  
  79. int any_post_action_scores;
  80.  
  81. /* True if any post-event scorekeepers are defined. */
  82.  
  83. int any_post_event_scores;
  84.  
  85. /* True if any turn-specific scorekeepers are defined. */
  86.  
  87. int any_turn_specific_scores;
  88.  
  89. /* The count of sides in the game when the last-side-wins scorekeeper
  90.    first tested. */
  91.  
  92. static int num_sides_originally;
  93.  
  94. /* Clear out any possible scorekeepers. */
  95.  
  96. void
  97. init_scorekeepers()
  98. {
  99.     scorekeepers = last_scorekeeper = NULL;
  100.     numscorekeepers = 0;
  101.     nextskid = 1;
  102.     any_pre_turn_scores = FALSE;
  103.     any_post_turn_scores = FALSE;
  104.     any_post_action_scores = FALSE;
  105.     any_post_event_scores = FALSE;
  106.     any_turn_specific_scores = FALSE;
  107. }
  108.  
  109. Scorekeeper *
  110. create_scorekeeper()
  111. {
  112.     Scorekeeper *sk = (Scorekeeper *) xmalloc(sizeof(Scorekeeper));
  113.  
  114.     /* Initialize any nonzero fields. */
  115.     sk->id = nextskid++;
  116.     sk->when = lispnil;
  117.     sk->who = lispnil;
  118.     sk->whomask = ALLSIDES;
  119.     sk->knownto = lispnil;
  120.     sk->trigger = lispnil;
  121.     sk->body = lispnil;
  122.     sk->record = lispnil;
  123.     sk->notes = lispnil;
  124.     sk->scorenum = -1;
  125.     /* Init the initial score to a disallowed value, this keeps it off the
  126.        side's scorecard. */
  127.     sk->initial = -10001;
  128.     sk->triggered = FALSE;
  129.     /* Add the new scorekeeper to the end of the list. */
  130.     if (last_scorekeeper != NULL) {
  131.     last_scorekeeper->next = sk;
  132.     last_scorekeeper = sk;
  133.     } else {
  134.     scorekeepers = last_scorekeeper = sk;
  135.     }
  136.     ++numscorekeepers;
  137.     return sk;
  138. }
  139.  
  140. Scorekeeper *
  141. find_scorekeeper(id)
  142. int id;
  143. {
  144.     Scorekeeper *sk;
  145.  
  146.     for_all_scorekeepers(sk) {
  147.     if (sk->id == id)
  148.       return sk;
  149.     }
  150.     return NULL;
  151. }
  152.  
  153. /* Allocate and fill in the initial score records for each side.  This
  154.    must happen after all scorekeepers have been defined. */
  155.  
  156. void
  157. init_scores()
  158. {
  159.     int score;
  160.     Side *side;
  161.     Scorekeeper *sk;
  162.     Obj *savedscores, *when;
  163.  
  164.     /* First count and index all the scorekeepers that maintain
  165.        a numeric score. */
  166.     numscores = 0;
  167.     for_all_scorekeepers(sk) {
  168.         if (sk->initial != -10001) {
  169.             sk->scorenum = numscores++;
  170.         }
  171.     }
  172.     /* Allocate an appropriately-sized scorecard for each side.  Note that a
  173.        particular position in the scorecard might not apply to all sides. */
  174.     for_all_sides(side) {
  175.     /* Collect any Lisp object that might have been stashed here
  176.        while reading a game module. */
  177.     savedscores = side->rawscores;
  178.     side->scores = NULL;
  179.     if (numscores > 0) {
  180.         side->scores = (short *) xmalloc(numscores * sizeof(short));
  181.         for_all_scorekeepers(sk) {
  182.         score = sk->initial;
  183.         /* Collect a saved score if there is one to collect. */
  184.         if (savedscores != NULL
  185.             && savedscores != lispnil
  186.             && numberp(car(savedscores))) {
  187.             score = c_number(car(savedscores));
  188.             savedscores = cdr(savedscores);
  189.         }
  190.         side->scores[sk->scorenum] = score;
  191.         }
  192.     }
  193.     }
  194.     /* Some kinds of scorekeepers are expensive to run, so we set flags to
  195.        indicate directly that we need to make the check. */
  196.     for_all_scorekeepers(sk) {
  197.         when = sk->when;
  198.         if (consp(when)) {
  199.         if (cdr(when) != lispnil) {
  200.         any_turn_specific_scores = TRUE;
  201.         }
  202.         when = car(when);
  203.     }
  204.     if (match_keyword(when, K_BEFORE_TURN)) {
  205.          any_pre_turn_scores = TRUE;
  206.     }
  207.     if (when == lispnil || match_keyword(when, K_AFTER_TURN)) {
  208.          any_post_turn_scores = TRUE;
  209.     }
  210.     if (match_keyword(when, K_AFTER_ACTION)) {
  211.          any_post_action_scores = TRUE;
  212.     }
  213.     if (match_keyword(when, K_AFTER_EVENT)) {
  214.          any_post_event_scores = TRUE;
  215.     }
  216.     }
  217.     /* Compute the number of sides in the game initially.  This is so
  218.        we don't force the game to end because (for whatever reason)
  219.        only one side was active from the beginning. */
  220.     num_sides_originally = 0;
  221.     for_all_sides(side) {
  222.     if (side->ingame)
  223.       ++num_sides_originally;
  224.     }
  225. }
  226.  
  227. /* Test all the scorekeepers that should be run immediately before any
  228.    side moves anything. */
  229.  
  230. void
  231. check_pre_turn_scores()
  232. {
  233.     Side *side;
  234.     Scorekeeper *sk;
  235.  
  236.     if (any_pre_turn_scores) {
  237.     for_all_scorekeepers(sk) {
  238.         if (match_keyword(sk->when, K_BEFORE_TURN)) {
  239.         for_all_sides(side) {
  240.             if (scorekeeper_applicable(side, sk)) {
  241.             run_scorekeeper(side, sk); 
  242.             } else {
  243.                 Dprintf("sk %d not applicable to %s\n",
  244.                     sk->id, side_desig(side));
  245.             }
  246.         }
  247.         }
  248.     }
  249.     }
  250. }
  251.  
  252. /* Test all the scorekeepers that should be run only at the end of a turn. */
  253.  
  254. void
  255. check_post_turn_scores()
  256. {
  257.     Side *side;
  258.     Scorekeeper *sk;
  259.  
  260.     if (any_post_turn_scores) {
  261.     for_all_scorekeepers(sk) {
  262.         Dprintf("Checking post-turn scorekeeper %d\n", sk->id);
  263.         if (sk->when == lispnil || match_keyword(sk->when, K_AFTER_TURN)) {
  264.         /* Decide whether the scorekeeper applies to one side
  265.                    or to the whole game. */
  266.             if (symbolp(sk->body)
  267.                 && match_keyword(sk->body, K_LAST_SIDE_WINS)) {
  268.             eval_sk_last_side_wins(sk);
  269.             } else {
  270.             for_all_sides(side) {
  271.             if (scorekeeper_applicable(side, sk)) {
  272.                 run_scorekeeper(side, sk); 
  273.             } else {
  274.                 Dprintf("sk %d not applicable to %s\n",
  275.                     sk->id, side_desig(side));
  276.             }
  277.             }
  278.         }
  279.         }
  280.     }
  281.     }
  282. }
  283.  
  284. void
  285. check_post_action_scores(unit, action, rslt)
  286. Unit *unit;
  287. Action *action;
  288. int rslt;
  289. {
  290.     Side *side;
  291.     Scorekeeper *sk;
  292.  
  293.     if (any_post_action_scores) {
  294.     Dprintf("Checking post-action scorekeepers\n");
  295.     for_all_scorekeepers(sk) {
  296.         if (match_keyword(sk->when, K_AFTER_ACTION)) {
  297.         if (sk->trigger == lispnil || sk->triggered) {
  298.             for_all_sides(side) {
  299.             if (scorekeeper_applicable(side, sk)) {
  300.                 run_scorekeeper(side, sk);
  301.                 } else {
  302.                     Dprintf("sk %d not applicable to %s\n",
  303.                         sk->id, side_desig(side));
  304.             }
  305.             }
  306.         }
  307.         }
  308.     }
  309.     }
  310. }
  311.  
  312. void
  313. check_post_event_scores(hevt)
  314. HistEvent *hevt;
  315. {
  316.     Side *side;
  317.     Scorekeeper *sk;
  318.  
  319.     if (any_post_event_scores) {
  320.     Dprintf("Checking post-event scorekeepers\n");
  321.     for_all_scorekeepers(sk) {
  322.         if (match_keyword(sk->when, K_AFTER_EVENT)) {
  323.         if (sk->trigger == lispnil || sk->triggered) {
  324.             for_all_sides(side) {
  325.             if (scorekeeper_applicable(side, sk)) {
  326.                 run_scorekeeper(side, sk); 
  327.                 } else {
  328.                     Dprintf("sk %d not applicable to %s\n",
  329.                         sk->id, side_desig(side));
  330.             }
  331.             }
  332.         }
  333.         }
  334.     }
  335.     }
  336. }
  337.  
  338. /* This is what actually does the test and effect of the scorekeeper
  339.    on the given side.  This can be expensive to run. */
  340.  
  341. void
  342. run_scorekeeper(side, sk)
  343. Side *side;
  344. Scorekeeper *sk;
  345. {
  346.     eval_sk_form(side, sk, sk->body);
  347. }
  348.  
  349. int
  350. eval_sk_form(side, sk, form)
  351. Side *side;
  352. Scorekeeper *sk;
  353. Obj *form;
  354. {
  355.     int val;
  356.     char *formtype;
  357.     Obj *test, *clauses, *clause, *rest;
  358.  
  359.     if (symbolp(form)) {
  360.         if (match_keyword(form, K_LAST_SIDE_WINS)) {
  361.             eval_sk_last_side_wins(sk);
  362.         return 0;
  363.         } else if (boundp(form)) {
  364.             return 0;
  365.         } else {
  366.             syntax_error(form, "scorekeeper body");
  367.             return 0;
  368.         }
  369.     } else if (consp(form) && symbolp(car(form))) {
  370.     formtype = c_string(car(form));
  371.     switch (keyword_code(formtype)) {
  372.       case K_IF:
  373.         test = cadr(form);
  374.         if (eval_sk_test(side, sk, test)) {
  375.             eval_sk_form(side, sk, car(cddr(form)));
  376.         }
  377.         break;
  378.       case K_COND:
  379.         /* Interpret the traditional cond form. */
  380.         for (clauses = cdr(form); clauses != lispnil; clauses = cdr(clauses)) {
  381.         clause = car(clauses);
  382.         test = car(clause);
  383.             if (eval_sk_test(side, sk, test)) {
  384.                 for (rest = cdr(clause); rest != lispnil; rest = cdr(rest)) {
  385.                 eval_sk_form(side, sk, car(rest));
  386.                 }
  387.                 /* Don't look at any more clauses. */
  388.                 break;
  389.             }
  390.         }
  391.         break;
  392.       case K_STOP:
  393.         run_error("game stopped by scorekeeper %d", sk->id);
  394.         break;
  395.       case K_WIN:
  396.         if (side->ingame)
  397.           side_wins(side, sk->id);
  398.         break;
  399.       case K_LOSE:
  400.         if (side->ingame)
  401.           side_loses(side, NULL, sk->id);
  402.         break;
  403.       case K_DRAW:
  404.         all_sides_draw();
  405.         break;
  406.       case K_END:
  407.         /* (should end the game, assign scores to all sides) */
  408.         break;
  409.       case K_SET:
  410.         /* (should only do if this actually *is* a numeric scorekeeper) */
  411.         side->scores[sk->scorenum] = eval_sk_form(side, sk, cadr(form));
  412.         return side->scores[sk->scorenum];
  413.       case K_ADD:
  414.         if (cdr(form) != lispnil) {
  415.         val = eval_sk_form(side, sk, cadr(form));
  416.         } else {
  417.             val = 1;
  418.         }
  419.         /* (should only do if this actually *is* a numeric scorekeeper) */
  420.         side->scores[sk->scorenum] += val;
  421.         return side->scores[sk->scorenum];
  422.       case K_SUM:
  423.         return sum_property(side, cdr(form));
  424.       default:
  425.         run_warning("unknown form type `%s' in scorekeeper %d", formtype, sk->id);
  426.     }
  427.     /* This is for those forms that don't really have values, but may appear in
  428.        a value-using context anyway. */
  429.     return 0;
  430.     } else if (numberp(form)) {
  431.         return c_number(form);
  432.     } else {
  433.         syntax_error(form, "scorekeeper body");
  434.     return 0;
  435.     }
  436. }
  437.  
  438. int
  439. sum_property(side, form)
  440. Side *side;
  441. Obj *form;
  442. {
  443.     int sum = 0, i, typevec[200];
  444.     Obj *sidelist = lispnil, *typelist = lispnil, *prop = lispnil;
  445.     Obj *filter = lispnil;
  446.     Unit *unit;
  447.     
  448.     if (typelist != lispnil) {
  449.         /* (should decide overall type of objects first) */
  450.     for (i = 0; i < 200; ++i)
  451.       typevec[i] = FALSE;
  452.     } else {
  453.     for (i = 0; i < 200; ++i)
  454.       typevec[i] = TRUE;
  455.     }
  456.     if (consp(form)) {
  457.     prop = car(form);
  458.     form = cdr(form);
  459.     }
  460.     if (sidelist != lispnil) {
  461.         /* (should let optional cadr designate some other side) */
  462.     } else {
  463.     if (1 /* iterating over units */) {
  464.         for_all_side_units(side, unit) {
  465.             if (in_play(unit)
  466.                 && typevec[unit->type]
  467.                 && (filter == lispnil || TRUE /*filter allows through*/)) {
  468.             if (prop != lispnil) {
  469.             if (symbolp(prop)
  470.                 && strcmp(c_string(prop), "point-value") == 0) {
  471.                 sum += point_value(unit);
  472.             } else {
  473.             }
  474.             } else {
  475.             sum += 1;
  476.             }
  477.         }
  478.         }
  479.     }
  480.     }   
  481.     return sum;
  482. }
  483.  
  484. int
  485. point_value(unit)
  486. Unit *unit;
  487. {
  488.     Obj *val;
  489.  
  490.     /* Incomplete units are always worthless. */
  491.     if (unit->cp > 0 && !completed(unit))
  492.       return 0;
  493.     if (unit_point_value(unit) >= 0)
  494.       return unit_point_value(unit);
  495.     return u_point_value(unit->type);
  496. }
  497.  
  498. int
  499. side_point_value(side)
  500. Side *side;
  501. {
  502.     int points;
  503.     Unit *unit;
  504.  
  505.     if (!side->point_value_valid) {
  506.     side->point_value_cache = 0;
  507.     for_all_side_units(side, unit) {
  508.         if ((in_play(unit) && completed(unit))
  509.         || (alive(unit) && unit->cp < 0)) {
  510.         side->point_value_cache += point_value(unit);
  511.         }
  512.     }
  513.     side->point_value_valid = TRUE;
  514.     }
  515.     return side->point_value_cache;
  516. }
  517.  
  518. /* Evaluate a given form with respect to the given scorekeeper and side. */
  519.  
  520. int
  521. eval_sk_test(side, sk, form)
  522. Side *side;
  523. Scorekeeper *sk;
  524. Obj *form;
  525. {
  526.     char *formtype;
  527.     Obj *arg1 = lispnil, *arg2 = lispnil, *rest;
  528.  
  529.     if (consp(form)) {
  530.     formtype = c_string(car(form));
  531.     if (consp(cdr(form)))
  532.       arg1 = cadr(form);
  533.     if (consp(cddr(form)))
  534.       arg2 = car(cddr(form));
  535.     switch (keyword_code(formtype)) {
  536.       case K_AND:
  537.         for (rest = cdr(form); rest != lispnil; rest = cdr(rest)) {
  538.         if (!eval_sk_form(side, sk, car(rest)))
  539.           return FALSE;
  540.         }
  541.         return TRUE;
  542.       case K_OR:
  543.         for (rest = cdr(form); rest != lispnil; rest = cdr(rest)) {
  544.         if (eval_sk_form(side, sk, car(rest)))
  545.           return TRUE;
  546.         }
  547.         return FALSE;
  548.       case K_NOT:
  549.         return (!eval_sk_form(side, sk, arg1));
  550.       case K_EQ:
  551.         return (eval_sk_form(side, sk, arg1) ==
  552.             eval_sk_form(side, sk, arg2));
  553.       case K_NE:
  554.         return (eval_sk_form(side, sk, arg1) !=
  555.             eval_sk_form(side, sk, arg2));
  556.       case K_LT:
  557.         return (eval_sk_form(side, sk, arg1) <
  558.             eval_sk_form(side, sk, arg2));
  559.       case K_LE:
  560.         return (eval_sk_form(side, sk, arg1) <=
  561.             eval_sk_form(side, sk, arg2));
  562.       case K_GT:
  563.         return (eval_sk_form(side, sk, arg1) >
  564.             eval_sk_form(side, sk, arg2));
  565.       case K_GE:
  566.         return (eval_sk_form(side, sk, arg1) >=
  567.             eval_sk_form(side, sk, arg2));
  568.       default:
  569.         run_warning("not a proper test");
  570.         return FALSE;
  571.     }
  572.     } else if (symbolp(form)) {
  573.         eval_symbol(form);
  574.     }
  575.     return FALSE;
  576. }
  577.  
  578. static void
  579. eval_sk_last_side_wins(sk)
  580. Scorekeeper *sk;
  581. {
  582.     Side *side2, *winner = NULL;
  583.     int numleft = 0, points;
  584.  
  585.     /* This is only meaningful in games with at least two sides. */
  586.     if (num_sides_originally >= 2) {
  587.     for_all_sides(side2) {
  588.         if (side2->ingame) {
  589.         points = side_point_value(side2);
  590.         Dprintf("%s has %d points worth of units\n",
  591.             side_desig(side2), points);
  592.         if (points == 0) {
  593.             side_loses(side2, NULL, sk->id);
  594.         } else {
  595.             ++numleft;
  596.             winner = side2;
  597.         }
  598.         }
  599.     }
  600.     if (numleft == 1) {
  601.         side_wins(winner, sk->id);
  602.     }
  603.     }
  604. }
  605.  
  606. /* Implement the effects of a side winning. */
  607.  
  608. void
  609. side_wins(side, why)
  610. Side *side;
  611. int why;
  612. {
  613.     /* Nothing happens to the side's units or people. */
  614.     side->status = 1;
  615.     record_event(H_SIDE_WON, ALLSIDES, side_number(side), why);
  616.     remove_side_from_game(side);
  617. }
  618.  
  619. /* Implement the effects of a side losing. */
  620.  
  621. void
  622. side_loses(side, side2, why)
  623. Side *side, *side2;
  624. int why;
  625. {
  626.     int x, y, s, s2, ux, uy;
  627.     Unit *unit;
  628.  
  629.     /* These should not happen, but a stupid AI might try, so just
  630.        and clear the mistaken side. */
  631.     if (side == side2) {
  632.     run_warning("losing to self, ignoring side");
  633.     side2 = NULL;
  634.     }
  635.     if (side2 != NULL && !side2->ingame) {
  636.     run_warning("losing to side not in game, ignoring side");
  637.     side2 = NULL;
  638.     }
  639.     if (side2 != NULL) {
  640.     /* Dispose of all of a side's units. */
  641.     for_all_units(unit) {
  642.         if (unit->side == side) {
  643.         if (in_play(unit)) {
  644.             ux = unit->x;  uy = unit->y;
  645.             change_unit_side(unit, side2, H_SIDE_LOST, NULL);
  646.             /* Everybody gets to see this change. */
  647.             all_see_cell(ux, uy);
  648.         } else {
  649.             /* Even out-of-play units need to have their side set. */
  650.             set_unit_side(unit, side2);
  651.         }
  652.         }
  653.     }
  654.     /* The people also change sides. */
  655.     if (people_sides_defined()) {
  656.         s = side_number(side);
  657.         s2 = side_number(side2);
  658.         for_all_cells(x, y) {
  659.         if (people_side_at(x, y) == s) {
  660.             set_people_side_at(x, y, s2);
  661.             all_see_cell(x, y);
  662.         }
  663.         }
  664.     }
  665.     /* Reset view coverage everywhere. */
  666.     if (!all_see_all) {
  667.         for_all_cells(x, y) {
  668.         set_cover(side, x, y, 0);
  669.         }
  670.     }
  671.     }
  672.     /* Add the mark of shame itself. */
  673.     side->status = -1;
  674.     record_event(H_SIDE_LOST, ALLSIDES, side_number(side), why);
  675.     remove_side_from_game(side);
  676. }
  677.  
  678. void
  679. all_sides_draw()
  680. {
  681.     Side *side;
  682.  
  683.     for_all_sides(side) {
  684.         if (side->ingame) {
  685.         side->status = 0;
  686.         record_event(H_SIDE_WITHDREW, ALLSIDES, side_number(side));
  687.         remove_side_from_game(side);
  688.     }
  689.     }
  690. }
  691.  
  692. /* Record the outcome of the game into the scorefile. */
  693.  
  694. void
  695. record_into_scorefile()
  696. {
  697.     int i;
  698.     int any_advantage_variation = FALSE, adv, adv2;
  699.     char *filename, *mversion;
  700.     Variant *variants, *var;
  701.     FILE *fp;
  702.     Side *side;
  703.  
  704.     /* (should make following code into a separate routine) */
  705.     adv = max(1, sidelist->advantage);
  706.     adv = (sidelist->player ? sidelist->player->advantage : adv);
  707.     for_all_sides(side) {
  708.     adv2 = max(1, sidelist->advantage);
  709.     adv2 = (sidelist->player ? sidelist->player->advantage : adv2);
  710.     if (adv != adv2) {
  711.         any_advantage_variation = TRUE;
  712.         break;
  713.     }
  714.     }
  715.     filename = SCOREFILE;
  716.     if (!empty_string(g_scorefile_name()))
  717.       filename = g_scorefile_name();
  718.     fp = open_scorefile_for_writing(filename);
  719.     if (fp != NULL) {
  720.     fprintf(fp, "(game");
  721.     fprintf(fp, " \"%s\"",
  722.         /* (should record this for comparison when displaying scores) */
  723.         (mainmodule->origmodulename
  724.          ? mainmodule->origmodulename
  725.          : mainmodule->name));
  726.     /* Record the module's version if defined. */
  727.     mversion = (mainmodule->origversion
  728.             ? mainmodule->origversion
  729.             : mainmodule->version);
  730.     if (!empty_string(mversion))
  731.       fprintf(fp, " (version \"%s\")", mversion);
  732.     /* Record all the choices of variant. */
  733.     variants = (mainmodule->origvariants
  734.             ? mainmodule->origvariants
  735.             : mainmodule->variants);
  736.     if (variants) {
  737.         fprintf(fp, " (variants");
  738.         for (i = 0; variants[i].id != lispnil; ++i) {
  739.         var = &(variants[i]);
  740.         if (symbolp(var->id)) {
  741.             fprintf(fp, " (%s", c_string(var->id));
  742.         } else {
  743.             fprintf(fp, " (%d", i);
  744.         }
  745.         if (var->hasintvalue) {
  746.             fprintf(fp, " %d", var->intvalue);
  747.         }
  748.         fprintf(fp, ")");
  749.         }
  750.         fprintf(fp, ")");
  751.     }
  752.     fprintf(fp, "\n");
  753.     /* Record all the participants and how they fared. */
  754.     fprintf(fp, "  (sides");
  755.     for_all_sides(side) {
  756.         fprintf(fp, " (%d", side_number(side));
  757.         if (side->everingame) {
  758.         fprintf(fp, " %s",
  759.             (side_won(side)
  760.              ? "won"
  761.              : (side_lost(side) ? "lost" : "drew")));
  762.         short_player_title(spbuf, side->player, NULL);
  763.         fprintf(fp, " \"%s\"", spbuf);
  764.         if (any_advantage_variation) {
  765.             /* (should have cached as "actual advantage"?) */
  766.             int advantage = max(1, side->advantage);
  767.             
  768.             advantage =
  769.               (side->player ? side->player->advantage : advantage);
  770.             fprintf(fp, " (+ %d)", advantage); 
  771.         }
  772.         if (numscores > 0) {
  773.             fprintf(fp, " (scores");
  774.             for (i = 0; i < numscores; ++i) {
  775.             fprintf(fp, " %d", side->scores[i]);
  776.             }
  777.             fprintf(fp, ")");
  778.         }
  779.         }
  780.         fprintf(fp, ")");
  781.     }
  782.     fprintf(fp, ")");
  783.     /* (should record other useful info about game, such as date(s) played) */
  784.     fprintf(fp, ")\n");
  785.     fclose(fp);
  786.     }
  787. }
  788.  
  789. int
  790. read_scorefile()
  791. {
  792.     int startlineno = 1, endlineno = 1;
  793.     int numrecs;
  794.     char *filename;
  795.     Obj *form;
  796.     FILE *fp;
  797.     ScoreRecord *sr;
  798.  
  799.     filename = SCOREFILE;
  800.     if (!empty_string(g_scorefile_name()))
  801.       filename = g_scorefile_name();
  802.     fp = open_scorefile_for_reading(filename);
  803.     if (fp != NULL) {
  804.     numrecs = 0;
  805.     /* Read everything in the file. */
  806.     while ((form = read_form(fp, &startlineno, &endlineno)) != lispeof) {
  807.         if (interp_score_record(form)) {
  808.         ++numrecs;
  809.         }
  810.     }
  811.     fclose(fp);
  812.     Dprintf("%d score records read.\n", numrecs);
  813.     for_all_score_records(sr) {
  814.         Dprintf("%s\n", sr->gamename);
  815.     }
  816.     return TRUE;
  817.     }
  818.     return FALSE;
  819. }
  820.  
  821. int
  822. interp_score_record(form)
  823. Obj *form;
  824. {
  825.     char *propname;
  826.     Obj *props, *prop;
  827.     ScoreRecord *sr;
  828.  
  829.     if (consp(form)
  830.     && symbolp(car(form))
  831.     /* (should) and symbol is 'game' */
  832.     && stringp(cadr(form))) {
  833.     sr = (ScoreRecord *) xmalloc(sizeof(ScoreRecord));
  834.     sr->gamename = c_string(cadr(form));
  835.     for_all_list(cddr(form), props) {
  836.         prop = car(props);
  837.         if (symbolp(car(prop))) {
  838.         propname = c_string(car(prop));
  839.         switch (keyword_code(propname)) {
  840.           case K_VERSION:
  841.             break;
  842.           case K_VARIANTS:
  843.             break;
  844.           default:
  845.             /* This is for keywords that may appear in a
  846.                score record but are not actually part of GDL. */
  847.             if (strcmp(propname, "sides") == 0) {
  848.             sr->sides = cdr(prop);
  849.             } else {
  850.             /* should complain? */
  851.             }
  852.             break;
  853.         }
  854.         }
  855.     }
  856.     sr->raw = form;
  857.     /* Add the record to the end of the list. */
  858.     if (records != NULL) {
  859.         last_record->next = sr;
  860.         last_record = sr;
  861.     } else {
  862.         records = last_record = sr;
  863.     }
  864.     return TRUE;
  865.     }
  866.     return FALSE;
  867. }
  868.  
  869. char *get_scores PARAMS ((Side *side));
  870.  
  871. char *
  872. get_scores(side)
  873. Side *side;
  874. {
  875.     char *buf = xmalloc(5000);
  876.     char buf2[BUFSIZE];
  877.     char *thisgame, *playername;
  878.     Obj *sds, *sd;
  879.     ScoreRecord *sr;
  880.  
  881.     thisgame = (mainmodule->origmodulename
  882.          ? mainmodule->origmodulename
  883.          : mainmodule->name);
  884.     if (thisgame == NULL)
  885.       return "???";
  886.     sprintf(buf, "Scores for \"%s\":\n", thisgame);
  887.     read_scorefile();
  888.     playername = NULL;
  889.     if (side != NULL) {
  890.     short_player_title(buf2, side->player, NULL);
  891.     playername = buf2;
  892.     }
  893.     if (1 /* summarize */) {
  894.     int wins, losses, plays;
  895.  
  896.     wins = losses = plays = 0;
  897.     for_all_score_records(sr) {
  898.         if (!empty_string(sr->gamename)
  899.         && strcmp(thisgame, sr->gamename) == 0) {
  900.         if (playername != NULL && sr->sides != NULL) {
  901.             for_all_list(sr->sides, sds) {
  902.             sd = car(sds);
  903.             if (strcmp(playername, c_string(car(cddr(sd)))) == 0) {
  904.                 if (strcmp("won", c_string(car(cdr(sd)))) == 0) {
  905.                 ++wins;
  906.                 } else if (strcmp("lost", c_string(car(cdr(sd)))) == 0) {
  907.                 ++losses;
  908.                 }
  909.             }
  910.             }
  911.         }
  912.         ++plays;
  913.         }
  914.     }
  915.     tprintf(buf, "%s won %d and lost %d of %d games played.\n",
  916.         "You", wins, losses, plays);
  917.     return buf;
  918.     }
  919.     /* List all the games explicitly. */
  920.     for_all_score_records(sr) {
  921.     if (!empty_string(sr->gamename)
  922.         && strcmp(thisgame, sr->gamename) == 0) {
  923.         if (playername == NULL || 1 /* playername != NULL */) {
  924.         if (sr->sides != NULL) {
  925.             for_all_list(sr->sides, sds) {
  926.             sd = car(sds);
  927.             tprintf(buf, "  %s %s",
  928.                 c_string(car(cddr(sd))), c_string(car(cdr(sd))));
  929.             }
  930.         }
  931.         } else {
  932.         }
  933.         tprintf(buf, "\n");
  934.         if (strlen(buf) > 4500)
  935.           break;
  936.     }
  937.     }
  938.     return buf;
  939. }
  940.  
  941. /* This is a general test of whether the given side should be trying
  942.    to win somehow, or if it can just goof off. */
  943.  
  944. int
  945. should_try_to_win(side)
  946. Side *side;
  947. {
  948.     Scorekeeper *sk;
  949.  
  950.     for_all_scorekeepers(sk) {
  951.     if (scorekeeper_applicable(side, sk)) {
  952.         return TRUE;
  953.     }
  954.     }
  955.     return FALSE;
  956. }
  957.